/* 
 * Evo
 * 
 * Marcin Krupowicz (marcin@krupowicz.eu)
 * Barbara Szymanek (basia.szymanek@gmail.com)
 * 
 * January, 2009
 *
 */

using System;
using System.Collections.Generic;
using System.Text;
using Evo;
using Evo.Operators;

namespace Evo
{
	/// <summary>
	/// Inner evolutionary algorithm, used only by SelfAdaptiveEvolutionaryAlgorithm
	/// </summary>
	/// <typeparam name="T"></typeparam>
    public class EvolutionaryAlgorithmWorker<T>: EvolutionaryAlgorithm<T> where T:IIndividual
    {
        #region fields
        RealIndividual ppbIndividual;
        List<int> crossoverOperatorsPosition = new List<int>();
        List<int> operatorsToExecute = new List<int>();
        int crossoverToExecute = -1;

        double bestOnStart;
        double bestAtTheEnd;
        double averageOnStart;
        double averageAtTheEnd;
        #endregion

        #region properties
		/// <summary>
		/// Individual standing for algorithm's probability vector
		/// </summary>
        public RealIndividual PPBIndividual
        {
            get { return ppbIndividual; }
            set
            {
                ppbIndividual = value;
                ppbIndividual.ObjectiveFunction = this.evaluate;
            }
        }

		/// <summary>
		/// Evolutionary operators of algorithm
		/// </summary>
        public new List<IOperator<T>> Operators
        {
            get { return operators; }
            set 
            { 
                operators = value;
                foreach (IOperator<T> op in operators)
                {
                    if ((op as CrossoverOperator<T>) != null)
                        crossoverOperatorsPosition.Add(operators.IndexOf(op));
                    else operatorsToExecute.Add(operators.IndexOf(op));
                }
            }
        }
       
        #endregion

        #region constructors
        public EvolutionaryAlgorithmWorker(int populationSize, int chromosomeLength, int maxIteration, bool verbose)
        :base(populationSize, chromosomeLength, maxIteration, verbose)
        {
            ppbIndividual = new RealIndividual();        
        }
        #endregion

        #region methods
        private double evaluate(IIndividual individual)
        {
			return (Math.Pow(bestOnStart / bestAtTheEnd, 2.0) + averageOnStart / averageAtTheEnd)/2.0;
        }

        private void updateMutationPpb()
        {
            for (int i = 0; i < operators.Count; i++)
            {
                if (!crossoverOperatorsPosition.Contains(i))
                {
                    MutationOperator<T> mutationOperator = (MutationOperator<T>)operators[i];
                    mutationOperator.Probability = ((RealChromosome)ppbIndividual.Chromosome)[i];
                }

            }
        }

        private int setCrossoverToExecute()
        {
            int maxInd = -1;
            double max = 0.0;
            double current;

            for (int i = 0; i < crossoverOperatorsPosition.Count; i++)
            {
                current = ((RealChromosome)ppbIndividual.Chromosome)[crossoverOperatorsPosition[i]];
                if(max < current )
                {
                    max = current;
                    maxInd = crossoverOperatorsPosition[i];
                }
            }

            return maxInd;
        }

        protected override void doIteration()
        {
            operatorsToExecute.Sort();
            IOperator<T> op;
            foreach(int i in operatorsToExecute)
            {                                                           
                op = Operators[i];
                population = op.Execute(population);
                population.Evaluate(fitnessScaling);        
            } 
        }

        public override void AddOperator(IOperator<T> newOperator)
        {
            base.AddOperator(newOperator);
            if( (newOperator as CrossoverOperator<T>) != null)
                crossoverOperatorsPosition.Add(operators.IndexOf(newOperator));
            else operatorsToExecute.Add(operators.IndexOf(newOperator));
        }

        public override void RunAlgorithm()
        {
			this.population.ObjectiveFunction = this.ObjectiveFunction;
            bestOnStart = Population.Best.Value;
            averageOnStart = Population.Average;
        
            //ustala ppb mutacji zgodnie z zalozeniami
            updateMutationPpb();
           
            //ustal ktory crossover ma byc na liscie operatorow
            operatorsToExecute.Remove(crossoverToExecute);
            crossoverToExecute = setCrossoverToExecute();
            operatorsToExecute.Add(crossoverToExecute);

            base.RunAlgorithm();
            
            bestAtTheEnd = Population.Best.Value;
            averageAtTheEnd = Population.Average;
        }
        #endregion
    }
}
